#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Net.Mail;
using NUnit.Framework;
using Newtonsoft.Utilities.Collections;
using System.Collections;
using Newtonsoft.Utilities.Testing;
using System.Linq;

namespace Newtonsoft.Utilities.Tests.Collections
{
  public class CollectionUtilsTests : TestsBase
  {
    [Test]
    public void ListEquals()
    {
      int[] a1;
      int[] a2;

      a1 = new int[] { 1, 2, 3 };
      a2 = new int[] { 1, 2, 3 };
      Assert.IsTrue(CollectionUtils.ListEquals(a1, a2));

      a2 = new int[] { 1, 2, 3, 4 };
      Assert.IsFalse(CollectionUtils.ListEquals(a1, a2));

      a2 = null;
      Assert.IsFalse(CollectionUtils.ListEquals(a1, a2));

      a1 = null;
      Assert.IsTrue(CollectionUtils.ListEquals(a1, a2));

      List<Version> b1;
      Version[] b2;
      
      b1 = new List<Version>(new Version[] { new Version(1, 0), new Version(2, 0) });
      b2 = new Version[] { new Version(1, 0), new Version(2, 0) };
      Assert.IsTrue(CollectionUtils.ListEquals(b1, b2));

      b1 = new List<Version>(new Version[] { null, null });
      b2 = new Version[] { null, null };
      Assert.IsTrue(CollectionUtils.ListEquals(b1, b2));
    }

    [Test]
    public void Minus()
    {
      int[] list = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
      int[] minus = new int[] {1, 3, 5, 7, 9};

      IList<int> result = CollectionUtils.Minus<int>(list, minus);

      Assert.IsNotNull(result);
      Assert.AreEqual(5, result.Count);
      for (int i = 0; i < 5; i++)
      {
        Assert.AreEqual(i * 2, result[i]);
      }
    }

    [Test]
    public void CreateList()
    {
      Queue queue = new Queue();

      queue.Enqueue(1);
      queue.Enqueue(2);

      List<int> intList = CollectionUtils.CreateList<int>(queue);
      Assert.AreEqual(2, intList.Count);
      Assert.AreEqual(1, intList[0]);
      Assert.AreEqual(2, intList[1]);

      queue.Enqueue("String");

      List<object> objectList = CollectionUtils.CreateList<object>(queue);
      Assert.AreEqual(3, objectList.Count);
      Assert.AreEqual(1, objectList[0]);
      Assert.AreEqual(2, objectList[1]);
      Assert.AreEqual("String", objectList[2]);
    }

    public class MockReadonlyCollection : ReadOnlyCollection<string>
    {
      public MockReadonlyCollection() : base(new string[0])
      {
      }
    }

    [Test]
    public void CreateAndPopulateList()
    {
      IList result;
      object testObject = new object();
      result = CollectionUtils.CreateAndPopulateList(typeof(ArrayList), delegate(IList list)
                                                                        {
                                                                          list.Add(1);
                                                                          list.Add(testObject);
                                                                          list.Add(new Version(1, 2, 3, 4));
                                                                        });

      Assert.IsNotNull(result);
      Assert.IsInstanceOfType(typeof(ArrayList), result);
      Assert.AreEqual(3, result.Count);
      Assert.AreEqual(1, result[0]);
      Assert.AreEqual(testObject, result[1]);
      Assert.AreEqual(new Version(1, 2, 3, 4), result[2]);

      result = CollectionUtils.CreateAndPopulateList(typeof(List<string>), delegate(IList list)
                                                                           {
                                                                             list.Add("1");
                                                                             list.Add("2");
                                                                             list.Add(null);
                                                                           });

      Assert.IsNotNull(result);
      Assert.IsInstanceOfType(typeof(List<string>), result);
      Assert.AreEqual(3, result.Count);
      Assert.AreEqual("1", result[0]);
      Assert.AreEqual("2", result[1]);
      Assert.AreEqual(null, result[2]);

      result = CollectionUtils.CreateAndPopulateList(typeof(Version[]), delegate(IList list)
                                                                        {
                                                                          list.Add(new Version(1, 0, 0, 0));
                                                                          list.Add(new Version(1, 0, 0, 1));
                                                                        });

      Assert.IsNotNull(result);
      Assert.IsInstanceOfType(typeof(Version[]), result);
      Assert.AreEqual(2, result.Count);
      Assert.AreEqual(new Version(1, 0, 0, 0), result[0]);
      Assert.AreEqual(new Version(1, 0, 0, 1), result[1]);

      result = CollectionUtils.CreateAndPopulateList(typeof(ReadOnlyCollection<int?>), delegate(IList list)
                                                                                       {
                                                                                         list.Add(1);
                                                                                         IList<int?> intLit = (IList<int?>)list;
                                                                                         intLit.Add(new int?());
                                                                                       });

      Assert.IsNotNull(result);
      Assert.IsInstanceOfType(typeof(ReadOnlyCollection<int?>), result);
      Assert.AreEqual(2, result.Count);
      Assert.AreEqual(1, result[0]);
      Assert.AreEqual(null, result[1]);

      result = CollectionUtils.CreateAndPopulateList(typeof(Collection<int>), delegate(IList list)
                                                                              {
                                                                                list.Add(1);
                                                                                list.Add(2);
                                                                              });

      Assert.IsNotNull(result);
      Assert.IsInstanceOfType(typeof(Collection<int>), result);
      Assert.AreEqual(2, result.Count);
      Assert.AreEqual(1, result[0]);
      Assert.AreEqual(2, result[1]);

      MailAddress address1 = new MailAddress("test1@test.com");
      MailAddress address2 = new MailAddress("test2@test.com");
      result = CollectionUtils.CreateAndPopulateList(typeof(MailAddressCollection), delegate(IList list)
                                                                                    {
                                                                                      list.Add(address1);
                                                                                      list.Add(address2);
                                                                                    });

      Assert.IsNotNull(result);
      Assert.IsInstanceOfType(typeof(MailAddressCollection), result);
      Assert.AreEqual(2, result.Count);
      Assert.AreEqual(address1, result[0]);
      Assert.AreEqual(address2, result[1]);
    }

    [Test]
    [ExpectedException(typeof(Exception), ExpectedMessage = "Read-only type Newtonsoft.Utilities.Tests.Collections.CollectionUtilsTests+MockReadonlyCollection does not have a public constructor that takes a type that implements System.Collections.Generic.IEnumerable`1[System.String].")]
    public void CreateAndPopulateListNonInstantableReadonlyCollection()
    {
      CollectionUtils.CreateAndPopulateList(typeof(MockReadonlyCollection), delegate { });
    }
  }
}
